#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "Utilitarios.h"
#include "HashALU.h"
#include "HashFIE.h"
#include "Alumno.h"
#include "ListaAlumno.h"
#include "ListaFiesta.h"
#include "ColaAlumno.h"
#include "Lectura.h"
#include "Master.h"
#include "Escritura.h"
#include "Interfaz.h"
#define ALUMNO "Alumno.txt"
#define FIESTA "Fiesta.txt"
#define ALUMNO "Alumno.txt"
#define ESPECIALIDAD "Especialidad.txt"
#define ASISTENCIA "Asistencia.txt"
#define FACULTAD "Facultad.txt"
#define INTERES "_Interes.txt"
#define REPORTE "_Reporte.txt"


Master iniciar(){
    Master master;
    
    //iniciar Hash's
    HashALU* hashALU = crear_HashALU(100);

    HashFIE* hashFIE = crear_HashFIE(20);
    
    HashESP* hashESP = crear_HashESP(15);

    ListaAlumno* listaAlu;
    ListaFiesta* listaFie;
    ListaEspecialidad* listaEsp;
    
    //iniciar listas
    listaAlu = crear_ListaAlumno();
    listaFie = crear_ListaFiesta();
    listaEsp = crear_ListaEspecialidad();
    
    
    lecturaArchivo_Especialidad(listaEsp,hashESP);
    lecturaArchivo_Alumno(listaAlu,hashESP,hashALU);
    lecturaArchivo_Fiesta(listaFie,hashFIE);
    lecturaArchivo_Asistencia(hashALU,hashFIE);
    lecturaArchivo_Interes(listaFie,hashALU);
   
    master.hashAlu = hashALU;
    master.hashEsp = hashESP;
    master.hashFie = hashFIE;
    master.listaAlu = listaAlu;
    master.listaFie = listaFie;
    master.listaEsp = listaEsp;
    
//    imprimir_HashESP(hashESP);
//    imprimir_HashALU(hashALU);
//    imprimir_HashFIE(hashFIE);
    
    //imprimir_ListaAlumno(listaAlu);
    //imprimir_ListaFiesta(listaFie);
    //imprime_ListaEspecialidad(listaEsp);
    
//    NodoListaFiesta* i;
//    for (i=listaFie->ini; i != NULL; i = i->sig){
//        printf("Cola Interes:\n");
//        imprimir_ColaAlumno(i->fiesta->interes);
//    }
    
//    NodoListaFiesta* i;
//    for (i=listaFie->ini; i != NULL; i = i->sig){
//        printf("Lista Asistencia:\n");
//        imprimir_ListaAlumno(i->fiesta->asistencia);
//        printf("\n\n");
//    }
   
    
    return master;
}

void registroDeAlumno(Master* master){
    int codEsp,codAl;
    char nombre[100], fecha[10], aux[100];
    int i;
    printf("1.1. REGISTRO DE ALUMNO: \n");
    printf("\n  Ingrese el codigo PUCP: ");
    fflush(stdin);
    scanf("%d",&codAl); getchar();   
    fflush(stdin);
    if (verificarExistencia(master->hashAlu,codAl)){
        mensaje("El alumno ya se encuentra registrado.");
    } else {
        printf("\n  Ingrese el nombre completo: ");
        //gets(nombre);
        gets(nombre); 
        fflush(stdin);
        printf("\n  Seleccione el codigo de la especialidad:\n");
        imprime_ListaEspecialidad(master->listaEsp);
        printf("\n  Ingrese el codigo de la especialidad: ");
        scanf("%d",&codEsp); getchar();
        fflush(stdin);
        printf("\n  Ingrese la fecha de nacimiento (dd/mm/aaa): ");
        strcpy(aux,nombre);
        gets(fecha);	
        fflush(stdin);
        Alumno* alumno = nuevo_Alumno(codAl,aux,codEsp,fecha,master->hashEsp);
        insertarFinal_ListaAlumno(master->listaAlu,alumno);
        inserta_HashALU(master->hashAlu,alumno);
        mensaje("Alumno registrado exitosamente.");
    }
 }
    
void registroDeFiesta(Master* master){
    char nombre[100];
    char fecha[11];
    int codigoFies;
    float costo;
    char aux[100];
    printf("1.2. REGISTRO DE FIESTA: \n");
    fflush(stdin);
    printf("\n  Ingrese el nombre: ");
    gets(nombre);
    fflush(stdin);
    strcpy(aux,nombre);
    printf("\n  Ingrese la fecha de realizacion (dd/mm/aaaa): ");
    scanf("%s",fecha);getchar();
    printf("\n  Ingrese el costo de la entrada: ");
    scanf("%f",&costo); getchar();
    codigoFies=master->listaFie->fin->fiesta->codigo;
    codigoFies=generarCodigo(master->hashFie,codigoFies);
    Fiesta* fiesta = nueva_Fiesta(codigoFies,nombre,costo,fecha);
    insertarFinal_ListaFiesta(master->listaFie,fiesta);
    inserta_HashFIE(master->hashFie,fiesta);
    mensaje("Fiesta registrada existosamente.");
}

int generarCodigo(HashFIE* hash,int codigo){
    codigo++;
    if(buscar_HashFIE(hash,codigo)!=NULL) return generarCodigo(hash,codigo);
    return codigo;
}

int verificarExistencia(HashALU* hash,int codAl){
    if(buscar_HashALU(hash,codAl)==NULL) return 0;
    return 1;
}

void finalizar(Master *master){
    system("cls");
    escritura_archivoAlumno(master->listaAlu);
    escritura_archivoAsistencia(master->listaFie);
    escritura_archivoInteres(master->listaFie);
    escritura_archivoFiesta(master->listaFie);
    printf("Sesion finalizada con exito.\n");
    printf("Gracias por usar un producto PUCP.\n");
}

void registroInteres(Master* master){
    Alumno* alumno;
    ListaFiesta* L ;
    int codAlu,opcion;
    char men[100];
    printf("3.1. REGISTRO DE INTERES EN UNA FISTA: \n");
    printf("\n  Ingrese su codigo de alumno PUCP: ");
    scanf("%d",&codAlu); getchar();
    if (verificarExistencia(master->hashAlu,codAlu)){
        //preguntar si actualizar o no
        alumno=buscar_HashALU(master->hashAlu, codAlu);
        printf("\n    El alumno ingresado es:\n\n");
        imprimir_Alumno(alumno);
        registrar:
        L = limitarPorFecha(master->listaFie);
        
        //se puede limitar la fiesta verificando que no sean fechas pasadas
        printf("\n\n  Seleccione el codigo de fiesta:\n\n");
        NodoListaFiesta* i;
        for (i=L->ini; i!=NULL; i = i->sig){
            printf("    %d %s\n",i->fiesta->codigo,i->fiesta->nombre);
        }
        printf("\n  Ingrese el codigo de la fiesta: ");
        scanf("%d",&opcion); getchar();
        Fiesta* fiesta=buscar_HashFIE(master->hashFie,opcion);
        if (esta_ColaAlumno(fiesta->interes,codAlu)){
            sprintf(men,"El alumno %d ya registro su interes por asistir a la fiesta %s.",codAlu,fiesta->nombre);
            mensaje(men);
        } else {
            encolar_ColaAlumno(fiesta->interes,alumno);
            sprintf(men,"\nSEl alumno %d ha registrado su interes por asistir a la fiesta %s exitosamente.",codAlu,fiesta->nombre);
            mensaje(men);
        }
        opcion = registrarInteresMismoAlumno();
        switch (opcion){
            case 0: menu_registroInteres(master); break;
            case 1: goto registrar;break;
        }
    } else {
         //registroDeAlumno(master);
         return;
    }
    
    
}

void registroManualAsistencia(Master* master){
    Alumno* alumno;
    ListaFiesta* L ;
    int codAlu,opcion;
    printf("Ingrese su codigo de alumno PUCP");
    scanf("%d",&codAlu);
     if (verificarExistencia(master->hashAlu,codAlu)){
        //preguntar si actualizar o no
    } else {
         //registroDeAlumno(master);
	return;
    }
    alumno=buscar_HashALU(master->hashAlu, codAlu);
    printf("El alumno ingresado es:\n");
    imprimir_Alumno(alumno);
    printf("\n");
    registrar:
    L = limitarPorCapacidad(limitarPorFecha(master->listaFie));
    imprimir_ListaFiesta(L);
    printf("Seleccione el codigo de fiesta a la cual se desea registrar\n");
    scanf("%d",&opcion);
    Fiesta* fiesta=buscar_HashFIE(master->hashFie,opcion);
    if (estaEnLista(fiesta->interes,codAlu)){
        printf("El alumno %d ya se encuentra registrado en la fiesta %s\n",codAlu,fiesta->nombre);
    }else
        insertarFinal_ListaFiesta(fiesta->interes,alumno);
    opcion=registrarInteresMismoAlumno();
    switch (opcion){
        case 0: menu_registroManuelAsistencia(master); break;
        case 1: goto registrar;break;
    }
}

ListaFiesta* limitarPorCapacidad(ListaFiesta* L){
    ListaFiesta* N = crear_ListaFiesta();
    NodoListaFiesta* i;
    for(i=L->ini;i != NULL; i=i->sig){
        if(i->fiesta->asistencia->cant < i->fiesta->capacidad && i->fiesta->capacidad !=-1){
            insertarFinal_ListaFiesta(N,i->fiesta);
        }
    }
    return N;   
}

ListaFiesta* limitarPorFecha(ListaFiesta* L){
    ListaFiesta* N = crear_ListaFiesta();
    int dia,mes,anho,acumuladoFecha,curDate;  
    time_t tiempo = time(0);
    struct tm *tlocal = localtime(&tiempo);
    dia =tlocal->tm_mday;
    mes = tlocal->tm_mon+1;
    anho = tlocal->tm_year + 1900;
    Fecha hoy;
    hoy.aa=anho;
    hoy.mm=mes;
    hoy.dd=dia;
    curDate = valor_Fecha(hoy);
    
    NodoListaFiesta* i;
    for(i=L->ini;i != NULL; i=i->sig){
        acumuladoFecha = valor_Fecha(i->fiesta->fecha);
        //acumuladoFecha = i->fiesta->fecha.aa*1000 + i->fiesta->fecha.mm*100 + i->fiesta->fecha.dd;
        if(acumuladoFecha>=curDate){
            insertarFinal_ListaFiesta(N,i->fiesta);
        }
    }
    return N;      
} 

int estaEnLista(ListaAlumno* lista, int codAlu){
    NodoListaAlumno *ptrRecorrido = lista->ini;
    while(ptrRecorrido != NULL){
        if(ptrRecorrido->alumno->codigo == codAlu) return 1;
        ptrRecorrido = ptrRecorrido->sig;
    }
    return 0;
}

void listadoAsistencia_Fiestas(Master* master){
    NodoListaFiesta* i; NodoListaAlumno* j;
    ListaFiesta* F; ListaAlumno* A;
    F = master->listaFie; //ordenar
    int campo;
    printf("Ingrese el modo de ordenamiento de las fiestas:\n");
    printf("    (0) Ordenar por nombre de fiesta\n");
    printf("    (1) Ordenar por código de la fiesta\n");
    printf("    (2) Ordenar por fecha de la fiesta\n");
    
    printf("\n  Campo: ");
    scanf("%d",&campo); getchar();
    
    if(campo==0) merge_sort_ListaFiesta(F,1);
    else if(campo==1) merge_sort_ListaFiesta(F,0);
    else if(campo == 2) merge_sort_ListaFiesta(F,3);
    
    printf("Ingrese el modo de ordenamiento de los alumnos:\n");
    printf("    (0) Ordenar por nombre de alumno\n");
    printf("    (1) Ordenar por código de especialidad\n");
    printf("\n  Campo: ");
    scanf("%d",&campo); getchar();
    
    
    printf("2.3.2 MOSTRAR ASISTENCIA DE TODAS LAS FIESTAS: \n");
    
    
    for (i=F->ini; i!=NULL; i = i->sig){
        A = i->fiesta->asistencia; 
        
        //ordenar       
        if(campo==0) merge_sort_ListaAlumno(A, 1);
        else if(campo==1) merge_sort_ListaAlumno(A,2);
        
        if (A->cant){
           char cad[100];
            sprintf(cad,"ASISTENCIA DE LA FIESTA: %s\n",i->fiesta->nombre);
            encabezado(cad);
            for (j=A->ini; j!=NULL; j = j->sig){
                imprimir_Alumno(j->alumno);
            } 
        }
        printf("\n\n\n");
    }
}

void listadoAsistencia_Fiesta(Master* master){
    NodoListaFiesta* i; NodoListaAlumno* j;
    ListaFiesta* F; ListaAlumno* A; Fiesta* fiesta;
    int cod;
    F = master->listaFie;
    printf("2.3.1 MOSTRAR ASISTENCIA DE FIESTA: \n");
    printf("\n  Seleccione el codigo de la fiesta:\n");
    for (i=F->ini; i!=NULL; i = i->sig){
        printf("    %d %s\n",i->fiesta->codigo,i->fiesta->nombre);
    }
    printf("\n  Ingrese el codigo de la fiesta: \n");
    scanf("%d",&cod);getchar();
    fiesta = buscar_HashFIE(master->hashFie,cod);
    A = fiesta->asistencia;
    //ordenar alumnos
    printf("Ingrese el modo de ordenamiento de los alumnos:\n");
    printf("    (0) Ordenar por nombre de alumno\n");
    printf("    (1) Ordenar por código de especialidad\n");
    printf("\n  Campo: ");
    scanf("%d",&cod); getchar();
    if(cod==0) merge_sort_ListaAlumno(A, 1);
    else if(cod==1) merge_sort_ListaAlumno(A,2);
    for (j=A->ini; j!=NULL; j = j->sig){
        imprimir_Alumno(j->alumno);
    }
    mensaje("");
}

void registroAutomaticoAsistencia(Master* master){
    int codFiesta; int cap;
    printf("4.1. REGISTRO AUTOMATICO DE ASISTENCIA A UNA FIESTA: \n");
    printf("\n\n  Seleccione el codigo de fiesta:\n\n");
        NodoListaFiesta* i;
        ListaFiesta* L = master->listaFie;
        for (i=L->ini; i!=NULL; i = i->sig){
            printf("    %d %s\n",i->fiesta->codigo,i->fiesta->nombre);
        }
        printf("\n  Ingrese el codigo de la fiesta: ");
        scanf("%d",codFiesta); getchar();
    Fiesta* fiesta = buscar_HashFIE(master->hashFie,codFiesta);
    Alumno* alumno;
    if (fiesta->capacidad == -1){
        fiesta->capacidad = cap;
        while (fiesta->interes->cant > 0 && fiesta->asistencia->cant < cap){
            alumno = desencolar_ColaAlumno(fiesta->interes);
            insertarFinal_ListaAlumno(fiesta->asistencia,alumno);
        }
        if (fiesta->interes->cant == 0 && fiesta->asistencia->cant == cap){
            mensaje("Se acabo la cola de interes y ademas, la asistencia llenó la capacidad.");
        } else if (fiesta->interes->cant == 0){
            mensaje("se acabo la cola de interes (no la capacidad)");
        } else if (fiesta->asistencia->cant == cap){
            mensaje("se lleno la capacidad máxima (no toda la cola)");
        }
        
    } 
}

void reporteRecaudacion(Master* master){
    ListaFiesta* lista = master->listaFie;
    NodoListaFiesta* nodo = lista->ini;
    Fecha fechaI;
    Fecha fechaF;
    float costoFiesta;
    float costoTotal = 0;
    int opcion;
    printf("Seleccion si quiere ver la recaudacion total o prefiere limitar por fecha 0/1\n");
    scanf("%d",&opcion);
    if(opcion == 1){
        printf("Ingrese el rango de fechas a evaluar en formato dd/mm/aa \n");
        printf("Ingrese fecha inicial : \n");
        scanf("%d %d %d", fechaI.dd, fechaI.mm, fechaI.aa);
        printf("Ingrese fecha fin : \n");
        scanf("%d %d %d", fechaF.dd, fechaF.mm, fechaF.aa);
        printf("Reporte de recaudacion entre el %d/%d/%d - %d/%d/%d :\n", fechaI.dd, fechaI.mm, fechaI.aa, fechaF.dd, fechaF.mm, fechaF.aa);
        while(nodo != NULL){
            if (fecha_en_rango(nodo->fiesta->fecha, fechaI, fechaF)){
                costoFiesta = nodo->fiesta->asistencia->cant * nodo->fiesta->costo;
                printf("Recaudacion de la fiesta %s -> s/. : %.2f \n",nodo->fiesta->nombre,costoFiesta);
                costoTotal = costoTotal + costoFiesta;
            }
            nodo=nodo->sig;
        }
        printf("Recaudacion total de todas las fiestas en el rango s/. %.2f",costoTotal);
    }
    if(opcion == 0){
        while(nodo != NULL){    
             costoFiesta = nodo->fiesta->asistencia->cant * nodo->fiesta->costo;
             if(costoFiesta != 0)
                 printf("Recaudacion de la fiesta %s -> s/. : %.2f \n",nodo->fiesta->nombre,costoFiesta);
             costoTotal = costoTotal + costoFiesta;
             nodo=nodo->sig;
        
        }
       printf("Recaudacion total de todas las fiestas  s/. %.2f\n",costoTotal);
    }
}

int fecha_en_rango(Fecha* fecha, Fecha inicio, Fecha fin){
    int final = valor_Fecha(fin);
    int prim = valor_Fecha(inicio);
    int cur = fecha->aa*1000 + fecha->mm*100 + fecha->dd;
    if((prim<cur) && (cur<final)) return 1;
    return 0;
}
